package com.example.sourcecodelearning.timer;

import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TimerWheel {

    private final int interval;
    private final int size;

    private final Queue<Task>[] queue;
    private int currentSlot;

    private volatile boolean isRunning = false;

    private final ThreadPoolExecutor threadPoolExecutor;

    @SuppressWarnings("unchecked")
    public TimerWheel(int interval, int size) {
        this.interval = interval;
        this.size = size;
        queue = new Queue[size];
        for (int i = 0; i < size; i++) {
            queue[i] = new LinkedBlockingQueue<>();
        }
        currentSlot = 0;
        threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100));
    }

    public void addTask(long delay, Task task) {
        int slot = (currentSlot + (int) (delay / interval)) % size;
        queue[slot].add(task);
    }

    public void start() {
        if (isRunning) {
            return;
        }
        isRunning = true;
        new Thread(this::run).start();
    }

    private void run() {
        while (isRunning) {
            Queue<Task> tasks = queue[currentSlot];
            while (!tasks.isEmpty()) {
                threadPoolExecutor.execute(tasks.poll());
            }
            currentSlot = (currentSlot + 1) % size;

            try {
                TimeUnit.MILLISECONDS.sleep(interval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void stop() {
        isRunning = false;
        threadPoolExecutor.shutdown();
    }
}